using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Common.Utilities.DLR;

namespace Workflows.Components
{
    /// <summary></summary>
    public delegate void ConnectorSettingChanged(Connector connector);

    /// <summary></summary>
    [Serializable]
    public class Connector
    {
        public event ConnectorSettingChanged ConnectorSettingChangedEvent;

        private Guid _ConnectorID;
        /// <summary></summary>
        [Browsable(true), Category("General")]
        public Guid ConnectorID
        {
            get { return _ConnectorID; }
            set
            {
                if (this._ConnectorID != value)
                {
                    _ConnectorID = value;
                    if (this.ConnectorSettingChangedEvent != null)
                        this.ConnectorSettingChangedEvent(this);
                }

            }
        }

        private string _ConnectorName;
        /// <summary></summary>
        [Browsable(true), Category("General")]
        public string ConnectorName
        {
            get { return _ConnectorName; }
            set
            {
                if (this._ConnectorName != value)
                {
                    _ConnectorName = value;
                    if (this.ConnectorSettingChangedEvent != null)
                        this.ConnectorSettingChangedEvent(this);
                }
            }
        }

        private ConnectorType _ConnectorType;
        /// <summary></summary>
        [Browsable(true), Category("General")]
        public ConnectorType ConnectorType
        {
            get
            {
                return this._ConnectorType;
            }
            set
            {
                this._ConnectorType = value;
            }
        }

        private Guid _FromComponentID;
        /// <summary></summary>
        public Guid FromComponentID
        {
            get
            {
                return this._FromComponentID;
            }
            set
            {
                this._FromComponentID = value;
            }
        }
        private Guid _ToComponentID;
        /// <summary></summary>
        public Guid ToComponentID
        {
            get
            {
                return this._ToComponentID;
            }
            set
            {
                this._ToComponentID = value;
            }
        }

        private List<CodeFieldMapper> _FieldMappers;
        /// <summary></summary>
        [Browsable(true), Category("Bindings")]
        public List<CodeFieldMapper> FieldMappers
        {
            get { return _FieldMappers; }
            set
            {
                this._FieldMappers = value;
            }
        }

        private Evaluable[] _Filter;
        /// <summary></summary>
        [Browsable(true), Category("Bindings")]
        public Evaluable[] Filter
        {
            get { return _Filter; }
            set { _Filter = value; }
        }

        /// <summary></summary>
        public Connector()
        {
            this._ConnectorID = Guid.NewGuid();
            this._ConnectorName = "Connector";
            this._FromComponentID = Guid.Empty;
            this._ToComponentID = Guid.Empty;
            this._FieldMappers=new List<CodeFieldMapper>();
            this._ConnectorType = Components.ConnectorType.Successful;
            this._Filter = null;
        }

        #region serialization & instantiation
        /// <summary></summary>
        public static XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode, Connector connector)
        {
            XmlNode connectorNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Connector");
            XmlDataUtil.UpdateAttribute(ref xDoc, connectorNode, "ConnectorID", connector.ConnectorID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, connectorNode, "ConnectorName", connector.ConnectorName);
            XmlDataUtil.UpdateAttribute(ref xDoc, connectorNode,"ConnectorType",((int)connector.ConnectorType).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, connectorNode, "FromComponentID",
                                        connector.FromComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, connectorNode, "ToComponentID", connector.ToComponentID.ToString());
            if (connector.FieldMappers != null)
            {
                XmlNode mapperRootNode = XmlDataUtil.AddElement(ref xDoc, connectorNode, "FieldMappers");
                foreach(CodeFieldMapper fieldMapper in connector.FieldMappers)
                {
                    XmlNode mapperNode = XmlDataUtil.AddElement(ref xDoc, mapperRootNode, "FieldMapper");
                    XmlDataUtil.UpdateAttribute(ref xDoc, mapperNode, "FromComponentID",
                                                fieldMapper.SrcComponentID.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc,mapperNode,"FromField",fieldMapper.SrcFieldName);
                    XmlDataUtil.UpdateAttribute(ref xDoc,mapperNode,"ToComponentID",fieldMapper.TgtComponentID.ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc,mapperNode,"ToField",fieldMapper.TgtFieldName);
                    XmlDataUtil.UpdateAttribute(ref xDoc,mapperNode,"ToName",fieldMapper.TgtInputName);
                    XmlDataUtil.UpdateAttribute(ref xDoc,mapperNode,"CodeSnippet",fieldMapper.AssignmentTransformation);
                }
                
            }

            if(connector.Filter !=null && connector.Filter.Length>0)
            {
                XmlNode filterNode = XmlDataUtil.AddElement(ref xDoc, connectorNode, "Filter");
                foreach (Evaluable eva in connector.Filter)
                {
                    XmlNode evaNode = XmlDataUtil.AddElement(ref xDoc, filterNode, "Evaluable");
                    XmlDataUtil.UpdateAttribute(ref xDoc,evaNode,"FieldName",eva.FieldName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, evaNode, "FieldType",
                                                ((int) eva.TypeToEvaluate).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, evaNode, "Operator",
                                                ((int) eva.Operator).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, evaNode, "CompareAgainst",
                                                eva.CompareAgainst.ToString());
                }
            }
            return connectorNode;
        }

        /// <summary></summary>
        public static Connector Instantiate(XmlNode xNode)
        {
            Connector connector = new Connector();
            connector.ConnectorID = new Guid(xNode.Attributes.GetNamedItem("ConnectorID").Value);
            connector.ConnectorName = xNode.Attributes.GetNamedItem("ConnectorName").Value;
            connector.ConnectorType = (ConnectorType) (int.Parse(xNode.Attributes.GetNamedItem("ConnectorType").Value));
            //Port fromPort = new Port();
            //XmlNode fromPortNode = xNode.SelectSingleNode("//FromPort");
            //fromPort.OwnerComponentID = new Guid(fromPortNode.Attributes.GetNamedItem("OwnerComponentID").Value);
            //fromPort.DataName = fromPortNode.Attributes.GetNamedItem("DataName").Value;
            //fromPort.Direction = (PortDirection)int.Parse(fromPortNode.Attributes.GetNamedItem("Direction").Value);
            connector.FromComponentID=new Guid(xNode.Attributes.GetNamedItem("FromComponentID").Value);
            connector.ToComponentID=new Guid(xNode.Attributes.GetNamedItem("ToComponentID").Value);
            connector.FieldMappers = new List<CodeFieldMapper>();
            XmlNodeList mapperNodes = xNode.SelectNodes("FieldMappers/FieldMapper");
            if(mapperNodes !=null && mapperNodes.Count>0)
            {
                foreach(XmlNode mapperNode in mapperNodes)
                {
                    CodeFieldMapper fieldMapper=new CodeFieldMapper();
                    fieldMapper.SrcComponentID=new Guid(mapperNode.Attributes.GetNamedItem("FromComponentID").Value);
                    fieldMapper.SrcFieldName = mapperNode.Attributes.GetNamedItem("FromField").Value;
                    fieldMapper.TgtComponentID=new Guid(mapperNode.Attributes.GetNamedItem("ToComponentID").Value);
                    fieldMapper.TgtFieldName = mapperNode.Attributes.GetNamedItem("ToField").Value;
                    fieldMapper.TgtInputName = mapperNode.Attributes.GetNamedItem("ToName").Value;
                    fieldMapper.AssignmentTransformation = mapperNode.Attributes.GetNamedItem("CodeSnippet").Value;
                    connector.FieldMappers.Add(fieldMapper);
                }
            }
            connector.Filter = null;
            XmlNodeList evaNodes = xNode.SelectNodes("Filter/Evaluable");
            if (evaNodes != null && evaNodes.Count>0)
            {
                List<Evaluable> evas=new List<Evaluable>();
                foreach (XmlNode evaNode in evaNodes)
                {
                    string fieldName = evaNode.Attributes.GetNamedItem("FieldName").Value;
                    SimpleDataType fieldType =
                        (SimpleDataType) int.Parse(evaNode.Attributes.GetNamedItem("FieldType").Value);
                    EvaluationOperator op =
                        (EvaluationOperator) int.Parse(evaNode.Attributes.GetNamedItem("Operator").Value);
                    object compareAgainst =
                        SimpleDataTypeUtil.ToDbValue(fieldType,
                                                     evaNode.Attributes.GetNamedItem("CompareAgainst").Value);
                    Evaluable evaluable = new Evaluable(fieldName, fieldType, op, compareAgainst);
                    evas.Add(evaluable);
                    
                }
                connector.Filter = evas.ToArray();
            }

            return connector;
        }
        #endregion
    }
}
